-[ c library "putil.c", header "putil.h" ]

/* parser utility functions. */

-[public] uterm_t *uterm_deep_copy(uterm_t *B)
{
	uterm_t *C;
	-[ allocate object C ]
	C->kind= B->kind;
	C->linenumber= linenumber_copy(B->linenumber);
	switch(B->kind) {
	case ut_number: case ut_strlit:
	case ut_word: case ut_macroarg:
	case ut_smacroarg: case ut_nmacroarg:
	case ut_wmacroarg:
		C->data= strdup(B->data);
		break;
	case  ut_ro_bulk: case ut_sq_bulk:
	case ut_cu_bulk:
		C->body= utermlist_deep_copy(B->body);
		break;
	}
	return C;
}



-[public] linenumber_t *linenumber_copy
	(linenumber_t *B)
{
	linenumber_t *C;
	if (!B) return 0;
	-[ allocate object C ]
	C->file= B->file;
	C->line= B->line;
	C->prev= linenumber_copy(B->prev);
	return C;
}

-[public] void uterm_free(uterm_t *T)
{
	linenumber_free(T->linenumber);
	switch(T->kind) {
	case ut_number: case ut_strlit:
	case ut_word: case ut_macroarg:
	case ut_smacroarg: case ut_nmacroarg:
	case ut_wmacroarg:
		free(T->data);
		break;
	case  ut_ro_bulk: case ut_sq_bulk:
	case ut_cu_bulk:
		utermlist_free(T->body);
		break;
	}
	free(T);
}



-[public] void utermlist_free(utermlist_t *L) {
	while(!utermlist_isempty(L))
		uterm_free(utermlist_destroy(L));
	free(L);
}

-[public] void linenumber_free(linenumber_t *L) {
	if (!L) return ;
	linenumber_free(L->prev);
	/* file names are not copied, just referenced.
	so, we do not free them */
	free(L);
}

-[public] utermlist_t* utermlist_deep_copy(utermlist_t *L) {
	utermlist_t *C;
	C= utermlist_new();
	-[list>for each T in *L, begin ]
		utermlist_append(C, uterm_deep_copy(T));
	-[ end ]
	return C;
}

-[ headers, begin ]
	!stdarg
	!stdlib parse
	!string
-[ end ]

+[ public types ]
#include <stdarg.h>
+[ end ]


-[public] int utermlist_count(utermlist_t *L) {
	int i;
	i=0;
	-[ list>for each Z in *L, begin] i++; -[end]
	return i;
}


-[public] uterm_t *uterm_shallow_copy(uterm_t *B)
{
	uterm_t *C;
	-[ allocate object C ]
	C->kind= B->kind;
	C->linenumber= linenumber_copy(B->linenumber);
	switch(B->kind) {
	case ut_number: case ut_strlit:
	case ut_word: case ut_macroarg:
	case ut_smacroarg: case ut_nmacroarg:
	case ut_wmacroarg:
		C->data= strdup(B->data);
		break;
	case  ut_ro_bulk: case ut_sq_bulk:
	case ut_cu_bulk:
		C->body= B->body;
		break;
	}
	return C;
}


-[private] utermlist_t *utermlist_deep_copy_with_lineno
	(utermlist_t *terms, linenumber_t *callsite)
{
	utermlist_t *R;
	R= utermlist_new();
	-[ list>for T ∈ *terms, begin]
		utermlist_append(R,
			uterm_deep_copy_with_lineno(T,callsite));
	-[end]
	return R;
}

-[public] uterm_t *uterm_deep_copy_with_lineno
	(uterm_t *B,linenumber_t *callsite)
{
	uterm_t *C;
	-[ allocate object C ]
	C->kind= B->kind;
	C->linenumber= linenumber_copy(B->linenumber);
	C->linenumber->prev= callsite;
	switch(B->kind) {
	case ut_number: case ut_strlit:
	case ut_word: case ut_macroarg:
	case ut_smacroarg: case ut_nmacroarg:
	case ut_wmacroarg:
		C->data= strdup(B->data);
		break;
	case  ut_ro_bulk: case ut_sq_bulk:
	case ut_cu_bulk:
		C->body= utermlist_deep_copy_with_lineno
			(B->body,callsite);
		break;
	}
	return C;
}

-[public] int utermlist_count_elems(utermlist_t *L) {
	int N;
	N= 0;
	-[list>for T ∈ *L, begin] N++; -[end]
	return N;
}

-[public] void utermlist_collect_elems
	(utermlist_t *L,int *n,uterm_t ***a)
{
	int N;

	N= utermlist_count_elems(L);
	*n= N;
	if (N)  {
		uterm_t **R;
		-[ R = allocate array N ]
		N=0;
		-[list>for T ∈ *L, begin] 
			R[N]= T;
			N++;
		-[end]
		*a= R;
	} else {
		*a= 0;
	}
}

-[public] void utermlist_append_destructive
	(utermlist_t *to, utermlist_t *from)
{
	uterm_t *Z;
	while((Z=utermlist_destroy(from)))
		utermlist_append(to,Z);
	free(from);
}


-[public] void utermlist_prepend_destructive
	(utermlist_t *from, utermlist_t *to)
{
	struct utermlist_t_NODE   *L, *F;

	if (utermlist_isempty(from)) return ;
	F= from->head.next;
	L= from->head.prev;

	L->next= to->head.next;
	to->head.next->prev= L;

	F->prev= &to->head;
	to->head.next= F;

	free(from);
}

-[public] utermlist_t *ulang_parse_string(char *str)
{
	return ulang_parse_buffer(str, strlen(str), "[builtin]");
}

-[public] uterm_t *uterm_simple
	(enum uterm_kind kind,char *data, linenumber_t *linenumber)
{
	uterm_t *T;
	-[ allocate object T ]
	T->kind= kind;
	T->data= data;
	T->linenumber= linenumber;
	return T;
}

-[public] void utermlist_toarray(utermlist_t *Z,uterm_t** V,int N) {
	int i;
	i= 0;
	-[ list>for K ∈ *Z, begin]
		if (i==N)
			return ;
		V[i]= K;
		i++;
	-[end]
}

-[public] uterm_t *uterm_cu_bulk
	(utermlist_t *body, linenumber_t *linenumber)
{
	uterm_t *T;
	-[ allocate object T ]
	T->kind= ut_cu_bulk;
	T->body= body;
	T->linenumber= linenumber;
	return T;
}


-[public] uterm_t *uterm_cu_bulk_of_one
	(uterm_t *term) 
{
	utermlist_t *body;
	body= utermlist_new();
	utermlist_append(body, term);
	return uterm_cu_bulk(body, term->linenumber);
}

